﻿using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.MultiTenancy;

namespace EcoSystem
{
    /// <summary>
    /// SQL脚本执行服务提供给Script引擎的封装类
    /// </summary>
    public class DataStoreScriptService : ApplicationService, IDataStoreScriptService
    {
        private readonly IRepository<SystemUser, Guid> _repository;

        public DataStoreScriptService(IRepository<SystemUser, Guid> repository)
        {
            _repository = repository;
        }

        public async Task<int> ExecuteSqlAsync( string sql, Dictionary<string, object> parameters = null)
        {
            var conn = await GetConnectionAsync();
            return await conn.ExecuteAsync(sql, parameters, commandType: CommandType.Text);
        }

        public async Task<int> ExecuteStoreProcedureAsync( string sql, Dictionary<string, object> parameters = null)
        {
            var conn = await GetConnectionAsync();
            return await conn.ExecuteAsync(sql, parameters, commandType: CommandType.StoredProcedure);
        }


        public async Task<dynamic> QueryFirstAsync( string sql, Dictionary<string, object> parameters = null)
        {
            var conn = await GetConnectionAsync();
            return await conn.QueryFirstAsync(sql, parameters, commandType: CommandType.Text);
        }

        public async Task<TResult> QueryFirstAsync<TResult>( string sql, Dictionary<string, object> parameters)
        {
            var conn = await GetConnectionAsync();
            return await conn.QueryFirstAsync(sql, parameters, commandType: CommandType.Text);
        }

        public async Task<IEnumerable<TResult>> QuerySqlAsync<TResult>( string sql, Dictionary<string, object> parameters = null)
        {
            var conn = await GetConnectionAsync();
            return await conn.QueryAsync<TResult>(sql, parameters, commandType: CommandType.Text);
        }

        public async Task<dynamic> QuerySqlAsync( string sql, Dictionary<string, object> parameters = null)
        {
            var conn = await GetConnectionAsync();
            return await conn.QueryAsync(sql, parameters, commandType: CommandType.Text);
        }

        public async Task<IEnumerable<TResult>> QueryStoreProcedureAsync<TResult>( string sql, Dictionary<string, object> parameters = null)
        {
            var conn = await GetConnectionAsync();
            return await conn.QueryAsync<TResult>(sql, parameters, commandType: CommandType.StoredProcedure);
        }

        public async Task<IEnumerable<dynamic>> QueryStoreProcedureAsync( string sql, Dictionary<string, object> parameters = null)
        {
            var conn = await GetConnectionAsync();
            return await conn.QueryAsync(sql, parameters, commandType: CommandType.StoredProcedure);
        }

        public async Task<TResult> QueryStoreProcedureFirstAsync<TResult>( string sql, Dictionary<string, object> parameters = null)
        {
            var conn = await GetConnectionAsync();
            return await conn.QueryFirstAsync<TResult>(sql, parameters, commandType: CommandType.StoredProcedure);
        }

        public async Task<dynamic> QueryStoreProcedureFirstAsync( string sql, Dictionary<string, object> parameters = null)
        {
            var conn = await GetConnectionAsync();
            return await conn.QueryFirstAsync(sql, parameters, commandType: CommandType.StoredProcedure);
        }

        public async Task<TResult> GetCacheAsync<TResult>(string key) where TResult : class
        {
            var cache = LazyServiceProvider.LazyGetService<IDistributedCache<TResult, string>>();
            return await cache.GetAsync(key);
        }

        public async Task SetCacheAsync<TResult>(string key, TResult value, DateTimeOffset? expiration = null) where TResult : class
        {
            var cache = LazyServiceProvider.LazyGetService<IDistributedCache<TResult, string>>();
            var options = expiration.HasValue ? new DistributedCacheEntryOptions() { AbsoluteExpiration = expiration } : null;
            await cache.SetAsync(key, value, options);
        }

        private async Task<DbConnection> GetConnectionAsync()
        {
            var context = await _repository.GetDbContextAsync();
            return context.Database.GetDbConnection();
        }
    }
}
